/*
 *  Author : WangBoJing , email : 1989wangbojing@gmail.com
 * 
 *  Copyright Statement:
 *  --------------------
 *  This software is protected by Copyright and the information contained
 *  herein is confidential. The software may not be copied and the information
 *  contained herein may not be used or disclosed except with the written
 *  permission of Author. (C) 2017
 * 
 *  功能说明：协程库核心头文件，定义宏、枚举、结构体和对外接口，
 *           统一管理协程状态、调度器结构、IO事件类型等核心概念
 */

#ifndef __NTY_COROUTINE_H__
#define __NTY_COROUTINE_H__

//#define _GNU_SOURCE // 编译时链接了
#include <dlfcn.h>  // 用于动态链接（系统调用Hook时使用dlsym）

#define _USE_UCONTEXT  // 启用ucontext_t实现上下文切换（注释则使用自定义CPU上下文）

// 基础依赖头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include <assert.h>
#include <inttypes.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <netinet/tcp.h>
#include <sys/socket.h>

#ifdef _USE_UCONTEXT
#include <ucontext.h>  // 系统上下文切换相关头文件
#endif

#include <sys/epoll.h>  // IO多路复用epoll头文件
#include <sys/poll.h>   // poll事件相关头文件

#include <errno.h>

#include "nty_queue.h"  // 队列/链表数据结构（TAILQ/LIST）
#include "nty_tree.h"   // 红黑树数据结构（RB树）

// 宏定义：核心配置参数
#define NTY_CO_MAX_EVENTS		(1024*1024)  // epoll最大监听事件数（100万）
#define NTY_CO_MAX_STACKSIZE	(128*1024)   // 协程默认栈大小（128KB，HTTP场景建议16KB，TCP场景4KB）

#define BIT(x)	 				(1 << (x))   // 位运算：设置第x位为1（用于协程状态标记）
#define CLEARBIT(x) 			~(1 << (x))  // 位运算：清除第x位（用于协程状态清除）

#define CANCEL_FD_WAIT_UINT64	1  // 启用fd+事件的uint64_t组合标记（用于IO等待协程管理）

// 协程执行函数类型定义：协程入口函数必须遵循此签名
typedef void (*proc_coroutine)(void *);

// 枚举：协程状态（核心状态机，控制协程调度逻辑）
typedef enum {
	NTY_COROUTINE_STATUS_WAIT_READ,        // 等待读事件（IO等待）
	NTY_COROUTINE_STATUS_WAIT_WRITE,       // 等待写事件（IO等待）
	NTY_COROUTINE_STATUS_NEW,              // 新建状态（未初始化）
	NTY_COROUTINE_STATUS_READY,            // 就绪状态（等待执行）
	NTY_COROUTINE_STATUS_EXITED,           // 退出状态（执行完毕）
	NTY_COROUTINE_STATUS_BUSY,             // 忙碌状态（正在执行）
	NTY_COROUTINE_STATUS_SLEEPING,         // 睡眠状态（主动休眠）
	NTY_COROUTINE_STATUS_EXPIRED,          // 过期状态（睡眠超时）
	NTY_COROUTINE_STATUS_FDEOF,            // 连接关闭状态（IO连接断开）
	NTY_COROUTINE_STATUS_DETACH,           // 分离状态（自动释放资源）
	NTY_COROUTINE_STATUS_CANCELLED,        // 取消状态（主动取消）
	NTY_COROUTINE_STATUS_PENDING_RUNCOMPUTE, // 等待计算资源（计算密集型协程）
	NTY_COROUTINE_STATUS_RUNCOMPUTE,       // 正在计算（计算密集型协程）
	NTY_COROUTINE_STATUS_WAIT_IO_READ,     // 等待IO读（细分IO状态）
	NTY_COROUTINE_STATUS_WAIT_IO_WRITE,    // 等待IO写（细分IO状态）
	NTY_COROUTINE_STATUS_WAIT_MULTI        // 等待多个事件（多IO等待）
} nty_coroutine_status;

// 枚举：计算型协程调度状态（区分计算资源是否占用）
typedef enum {
	NTY_COROUTINE_COMPUTE_BUSY,  // 计算资源忙碌
	NTY_COROUTINE_COMPUTE_FREE   // 计算资源空闲
} nty_coroutine_compute_status;

// 枚举：协程IO事件类型（读/写）
typedef enum {
	NTY_COROUTINE_EV_READ,  // 读事件
	NTY_COROUTINE_EV_WRITE  // 写事件
} nty_coroutine_event;

// 数据结构：协程链表头（LIST结构，用于管理忙碌协程）
LIST_HEAD(_nty_coroutine_link, _nty_coroutine);
// 数据结构：协程队列头（TAILQ结构，FIFO，用于就绪协程）
TAILQ_HEAD(_nty_coroutine_queue, _nty_coroutine);
// 数据结构：睡眠协程红黑树头（按睡眠时间排序，快速查找过期协程）
RB_HEAD(_nty_coroutine_rbtree_sleep, _nty_coroutine);
// 数据结构：IO等待协程红黑树头（按fd排序，快速查找IO就绪协程）
RB_HEAD(_nty_coroutine_rbtree_wait, _nty_coroutine);

// 类型重定义：简化结构体名称
typedef struct _nty_coroutine_link nty_coroutine_link;
typedef struct _nty_coroutine_queue nty_coroutine_queue;
typedef struct _nty_coroutine_rbtree_sleep nty_coroutine_rbtree_sleep;
typedef struct _nty_coroutine_rbtree_wait nty_coroutine_rbtree_wait;

// 结构体：自定义CPU上下文（不使用ucontext时启用，直接操作寄存器）
#ifndef _USE_UCONTEXT
typedef struct _nty_cpu_ctx {
	void *esp; // 栈指针（Extended Stack Pointer）
	void *ebp; // 基址指针（Extended Base Pointer）
	void *eip; // 指令指针（Extended Instruction Pointer）
	void *edi; // 目的变址寄存器
	void *esi; // 源变址寄存器
	void *ebx; // 基址寄存器
	void *r1;  // 通用寄存器（x86_64扩展）
	void *r2;  // 通用寄存器
	void *r3;  // 通用寄存器
	void *r4;  // 通用寄存器
	void *r5;  // 通用寄存器
} nty_cpu_ctx;
#endif

/// 结构体：协程调度器（核心管理者，管理所有协程和资源）
typedef struct _nty_schedule {
	uint64_t birth;                          // 调度器创建时间（微秒级）
#ifdef _USE_UCONTEXT
	ucontext_t ctx;                          // 调度器上下文（ucontext实现）
#else
	nty_cpu_ctx ctx;                         // 调度器上下文（自定义CPU寄存器）
#endif
	void *stack;                             // 调度器栈空间（共享给当前执行的协程）
	size_t stack_size;                       // 调度器栈大小
	int spawned_coroutines;                  // 已创建的协程总数
	uint64_t default_timeout;                // 默认超时时间（3秒，单位微秒）
	struct _nty_coroutine *curr_thread;      // 当前正在执行的协程
	int page_size;                           // 系统内存页大小（用于内存对齐）

	int poller_fd;                           // epoll文件描述符（IO多路复用句柄）
	int eventfd;                             // 事件通知fd（用于唤醒epoll等待）
	struct epoll_event eventlist[NTY_CO_MAX_EVENTS]; // epoll事件列表
	int nevents;                             // epoll返回的事件数

	int num_new_events;                      // 待处理的新事件数
	pthread_mutex_t defer_mutex;             // 延迟队列互斥锁（线程安全）

	nty_coroutine_queue ready;               // 就绪协程队列（TAILQ，FIFO）
	nty_coroutine_queue defer;               // 延迟执行队列（TAILQ）

	nty_coroutine_link busy;                 // 忙碌协程链表（LIST）
	
	nty_coroutine_rbtree_sleep sleeping;     // 睡眠协程红黑树（按睡眠时间排序）
	nty_coroutine_rbtree_wait waiting;       // IO等待协程红黑树（按fd排序）

	//private 私有字段（内部使用，不对外暴露）

} nty_schedule;

/// 结构体：协程对象（单个协程的核心数据结构）
typedef struct _nty_coroutine {

	//private 私有字段（内部使用）
	
#ifdef _USE_UCONTEXT
	ucontext_t ctx;                          // 协程上下文（ucontext实现）
#else
	nty_cpu_ctx ctx;                         // 协程上下文（自定义CPU寄存器）
#endif
	proc_coroutine func;                     // 协程入口函数
	void *arg;                               // 协程入口函数参数
	void *data;                              // 协程私有数据（用户自定义）
	size_t stack_size;                       // 协程栈大小
	size_t last_stack_size;                  // 上次执行时的栈大小（用于内存优化）
	
	nty_coroutine_status status;             // 协程当前状态（核心状态机）
	nty_schedule *sched;                     // 所属调度器指针（关联调度器）

	uint64_t birth;                          // 协程创建时间（微秒级）
	uint64_t id;                             // 协程ID（自增唯一标识）
#if CANCEL_FD_WAIT_UINT64
	int fd;                                  // IO等待的文件描述符
	unsigned short events;                   // 等待的IO事件（POLL_IN/POLL_OUT）
#else
	int64_t fd_wait;                         // fd+事件组合标记（uint64_t存储）
#endif
	char funcname[64];                       // 协程函数名（调试用）
	struct _nty_coroutine *co_join;          // 等待当前协程退出的协程（join机制）

	void **co_exit_ptr;                      // 协程退出状态指针（用于join获取结果）
	void *stack;                             // 协程栈空间（保存上下文时使用）
	void *ebp;                               // 协程栈基址指针（用于栈内存优化）
	uint32_t ops;                             // 执行操作数（用于协程调度优先级）
	uint64_t sleep_usecs;                    // 睡眠到期时间（微秒级）

	RB_ENTRY(_nty_coroutine) sleep_node;     // 睡眠红黑树节点（用于红黑树插入）
	RB_ENTRY(_nty_coroutine) wait_node;      // IO等待红黑树节点（用于红黑树插入）

	LIST_ENTRY(_nty_coroutine) busy_next;    // 忙碌链表节点（链表连接）

	TAILQ_ENTRY(_nty_coroutine) ready_next;  // 就绪队列节点（队列连接）
	TAILQ_ENTRY(_nty_coroutine) defer_next;  // 延迟队列节点（队列连接）
	TAILQ_ENTRY(_nty_coroutine) cond_next;   // 条件变量队列节点（队列连接）

	TAILQ_ENTRY(_nty_coroutine) io_next;     // IO事件队列节点（队列连接）
	TAILQ_ENTRY(_nty_coroutine) compute_next;// 计算队列节点（队列连接）

	// IO操作相关参数（存储IO请求的缓冲区、长度、fd等）
	struct {
		void *buf;       // IO缓冲区
		size_t nbytes;   // 要读取/写入的字节数
		int fd;          // IO文件描述符
		int ret;         // IO操作返回值
		int err;         // IO操作错误码
	} io;

	struct _nty_coroutine_compute_sched *compute_sched; // 计算型协程调度器
	int ready_fds;                           // 就绪的IO文件描述符数（多fd等待）
	struct pollfd *pfds;                     // poll事件数组（多fd等待）
	nfds_t nfds;                             // poll事件数（多fd等待）
} nty_coroutine;

/// 结构体：计算型协程调度器（专门管理计算密集型协程）
typedef struct _nty_coroutine_compute_sched {
#ifdef _USE_UCONTEXT
	ucontext_t ctx;                          // 计算调度器上下文（ucontext实现）
#else
	nty_cpu_ctx ctx;                         // 计算调度器上下文（自定义CPU寄存器）
#endif
	nty_coroutine_queue coroutines;          // 计算型协程队列

	nty_coroutine *curr_coroutine;           // 当前正在执行的计算型协程

	pthread_mutex_t run_mutex;               // 运行互斥锁（线程安全）
	pthread_cond_t run_cond;                 // 运行条件变量（唤醒计算协程）

	pthread_mutex_t co_mutex;                // 协程队列互斥锁（线程安全）
	LIST_ENTRY(_nty_coroutine_compute_sched) compute_next; // 计算调度器链表节点
	
	nty_coroutine_compute_status compute_status; // 计算资源状态（忙碌/空闲）
} nty_coroutine_compute_sched;

// 全局变量：线程私有数据键（每个线程一个调度器）
extern pthread_key_t global_sched_key;

// 内联函数：获取当前线程的协程调度器
static inline nty_schedule *nty_coroutine_get_sched(void) {
	return pthread_getspecific(global_sched_key); // 从线程私有数据中获取调度器
}

// 内联函数：计算两个时间戳的差值（微秒级）
static inline uint64_t nty_coroutine_diff_usecs(uint64_t t1, uint64_t t2) {
	return t2 - t1; // t2（当前时间） - t1（起始时间）
}

// 内联函数：获取当前时间（微秒级，用于超时计算）
static inline uint64_t nty_coroutine_usec_now(void) {
	struct timeval t1 = {0, 0};
	gettimeofday(&t1, NULL); // 获取秒和微秒

	return t1.tv_sec * 1000000 + t1.tv_usec; // 转换为总微秒数
}

// 函数声明：epoll创建（IO多路复用句柄创建）
int nty_epoller_create(void);

// 函数声明：取消协程的IO事件（从epoll中移除）
void nty_schedule_cancel_event(nty_coroutine *co);
// 函数声明：注册协程的IO事件（添加到epoll监听）
void nty_schedule_sched_event(nty_coroutine *co, int fd, nty_coroutine_event e, uint64_t timeout);

// 函数声明：唤醒睡眠协程（从睡眠红黑树移除，改为就绪状态）
void nty_schedule_desched_sleepdown(nty_coroutine *co);
// 函数声明：让协程进入睡眠状态（添加到睡眠红黑树）
void nty_schedule_sched_sleepdown(nty_coroutine *co, uint64_t msecs);

// 函数声明：唤醒IO等待协程（从IO红黑树移除）
nty_coroutine* nty_schedule_desched_wait(int fd);
// 函数声明：让协程进入IO等待状态（添加到IO红黑树）
void nty_schedule_sched_wait(nty_coroutine *co, int fd, unsigned short events, uint64_t timeout);

// 函数声明：启动调度器（开始协程调度循环）
void nty_schedule_run(void);

// 函数声明：注册epoll触发事件（用于唤醒epoll等待）
int nty_epoller_ev_register_trigger(void);
// 函数声明：epoll等待IO事件（带超时）
int nty_epoller_wait(struct timespec t);
// 函数声明：恢复协程执行（上下文切换到协程）
int nty_coroutine_resume(nty_coroutine *co);
// 函数声明：释放协程资源（内存、栈空间）
void nty_coroutine_free(nty_coroutine *co);
// 函数声明：创建协程（初始化协程对象，添加到就绪队列）
int nty_coroutine_create(nty_coroutine **new_co, proc_coroutine func, void *arg);
// 函数声明：协程主动挂起（上下文切换回调度器）
void nty_coroutine_yield(nty_coroutine *co);

// 函数声明：协程睡眠（指定毫秒数，进入睡眠状态）
void nty_coroutine_sleep(uint64_t msecs);

// 封装的系统调用：Socket相关（自动适配协程，非阻塞+IO等待）
int nty_socket(int domain, int type, int protocol);
int nty_accept(int fd, struct sockaddr *addr, socklen_t *len);
ssize_t nty_recv(int fd, void *buf, size_t len, int flags);
ssize_t nty_send(int fd, const void *buf, size_t len, int flags);
int nty_close(int fd);
int nty_poll(struct pollfd *fds, nfds_t nfds, int timeout);
int nty_connect(int fd, struct sockaddr *name, socklen_t namelen);

ssize_t nty_sendto(int fd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t nty_recvfrom(int fd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

#define COROUTINE_HOOK  // 启用系统调用Hook（自动拦截socket/recv等函数）

#ifdef  COROUTINE_HOOK

// 函数指针类型定义：对应系统调用的签名
typedef int (*socket_t)(int domain, int type, int protocol);
extern socket_t socket_f;  // 原始socket函数指针

typedef int(*connect_t)(int, const struct sockaddr *, socklen_t);
extern connect_t connect_f; // 原始connect函数指针

typedef ssize_t(*read_t)(int, void *, size_t);
extern read_t read_f;      // 原始read函数指针

typedef ssize_t(*recv_t)(int sockfd, void *buf, size_t len, int flags);
extern recv_t recv_f;      // 原始recv函数指针

typedef ssize_t(*recvfrom_t)(int sockfd, void *buf, size_t len, int flags,
        struct sockaddr *src_addr, socklen_t *addrlen);
extern recvfrom_t recvfrom_f; // 原始recvfrom函数指针

typedef ssize_t(*write_t)(int, const void *, size_t);
extern write_t write_f;    // 原始write函数指针

typedef ssize_t(*send_t)(int sockfd, const void *buf, size_t len, int flags);
extern send_t send_f;      // 原始send函数指针

typedef ssize_t(*sendto_t)(int sockfd, const void *buf, size_t len, int flags,
        const struct sockaddr *dest_addr, socklen_t addrlen);
extern sendto_t sendto_f;  // 原始sendto函数指针

typedef int(*accept_t)(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
extern accept_t accept_f;  // 原始accept函数指针

// new-syscall
typedef int(*close_t)(int);
extern close_t close_f;    // 原始close函数指针

// 函数声明：初始化Hook（获取原始系统调用函数指针）
int init_hook(void);

/*
// 可选Hook的系统调用（当前注释未启用）
typedef int(*fcntl_t)(int __fd, int __cmd, ...);
extern fcntl_t fcntl_f;

typedef int (*getsockopt_t)(int sockfd, int level, int optname,
        void *optval, socklen_t *optlen);
extern getsockopt_t getsockopt_f;

typedef int (*setsockopt_t)(int sockfd, int level, int optname,
        const void *optval, socklen_t optlen);
extern setsockopt_t setsockopt_f;
*/

#endif

#endif